#pragma once

#include <iostream>
#include <sstream>
#include <cstdio>
#include <cstdarg>
#include <ctime>
#include <string>
#include <vector>
#include <cstring>
#include <thread>
#include <mutex>
#include <memory>

#ifdef _WIN32
#include <windows.h> // Windows 平台需要包含 windows.h
#else
#include <locale>    // Linux 和 macOS 需要包含 locale
#endif

#include "LogFileNodeManager.hpp"

#define LOGFILE "./log/server" // 日志文件路径

// 宏开关：默认同时启用控制台和文件日志（按需注释）
#define LOG_TO_CONSOLE 1 // 启用控制台日志（带颜色）
#define LOG_TO_FILE 1    // 启用文件日志（无颜色）
#define LOG_SWITCH 1      // 总日志开关
#define LOG_DEBUG 1       // 调试日志开关

#define LOG_BUFFER_SIZE 1024 // 日志缓冲区初始大小


// 简化日志调用接口
#define log_debug(message, ...)  yzhzc::log::LogService::GetInstance()->log( yzhzc::log::LogService::debug, __FILE__, __LINE__, message, ##__VA_ARGS__)
#define log_info(message, ...)  yzhzc::log::LogService::GetInstance()->log( yzhzc::log::LogService::info, __FILE__, __LINE__, message, ##__VA_ARGS__)
#define log_warn(message, ...)  yzhzc::log::LogService::GetInstance()->log( yzhzc::log::LogService::warn, __FILE__, __LINE__, message, ##__VA_ARGS__)
#define log_error(message, ...)  yzhzc::log::LogService::GetInstance()->log( yzhzc::log::LogService::error, __FILE__, __LINE__, message, ##__VA_ARGS__)
#define log_fatal(message, ...)  yzhzc::log::LogService::GetInstance()->log( yzhzc::log::LogService::fatal, __FILE__, __LINE__, message, ##__VA_ARGS__)


namespace yzhzc
{
namespace log
{

struct FileRule
{
    FileRule(const char* filePath = LOGFILE,
        TimeUnit genPolicy = TimeUnit::DAILY, int genValue = 1,
        TimeUnit purgePol = TimeUnit::DAILY, int purgeVal = 7)
        : _filePath(filePath)
        , _genPolicy(genPolicy)
        , _genValue(genValue)
        , _purgePol(purgePol)
        , _purgeVal(purgeVal)
    {}

    std::string _filePath;         // 文件生成路径

    TimeUnit _genPolicy;   // 文件生成策略
    int _genValue;                       // 文件生成值

    TimeUnit _purgePol;    // 文件清理策略
    int _purgeVal;                       // 文件清理值
};

class LogService
{
public:
    // 日志级别枚举
    enum LogLevel
    {
        debug = 0,
        info = 1,
        warn = 2,
        error = 3,
        fatal = 4,
        level_count
    };

private:
    // 日志级别字符串映射
    const char* gLevelMap[level_count] = {
        "DEBUG", "INFO", "WARN", "ERROR", "FATAL" };

    const char* RESET = "\033[0m";                // 重置颜色（RESET）
    const char* BOLD_RED = "\033[1m\033[31m";     // 加粗红色（BOLD_RED）
    const char* BOLD_GREEN = "\033[1m\033[32m";   // 加粗绿色（BOLD_GREEN）
    const char* BOLD_YELLOW = "\033[1m\033[33m";  // 加粗黄色（BOLD_YELLOW）
    const char* BOLD_MAGENTA = "\033[1m\033[35m"; // 加粗品红（BOLD_MAGENTA）
    const char* BOLD_BLUE = "\033[1m\033[34m";    // 加粗品红（BOLD_MAGENTA）
    const char* BOLD_CYAN = "\033[1m\033[36m";    // 加粗品红（BOLD_MAGENTA）
    const char* BOLD_WHITE = "\033[1m\033[37m";   // 加粗白色（BOLD_WHITE）

    const char* CYAN = "\033[36m";    // 青色（CYAN）
    const char* BLUE = "\033[34m";    // 蓝色（BLUE）
    const char* MAGENTA = "\033[35m"; // 品红（MAGENTA）
    const char* BLACK = "\033[30m";   // 黑色（BLACK）
    const char* RED = "\033[31m";     // 红色（RED）
    const char* GREEN = "\033[32m";   // 绿色（GREEN）
    const char* YELLOW = "\033[33m";  // 黄色（YELLOW）
    const char* WHITE = "\033[37m";   // 白色（WHITE）

    const char* BG_BLACK = "\033[48;5;0m";   // 背景黑色（BG_BLACK）
    const char* BG_RED = "\033[48;5;1m";     // 背景红色（BG_RED）
    const char* BG_GREEN = "\033[48;5;2m";   // 背景绿色（BG_GREEN）
    const char* BG_YELLOW = "\033[48;5;3m";  // 背景黄色（BG_YELLOW）
    const char* BG_BLUE = "\033[48;5;4m";    // 背景蓝色（BG_BLUE）
    const char* BG_MAGENTA = "\033[48;5;5m"; // 背景品红（BG_MAGENTA）
    const char* BG_CYAN = "\033[48;5;6m";    // 背景青色（BG_CYAN）
    const char* BG_WHITE = "\033[48;5;7m";   // 背景白色（BG_WHITE）

public:
    // 获取单例实例
    static LogService* GetInstance()
    {
        std::call_once(_onceFlag, []() { _instance.reset(new LogService()); });
        return _instance.get();
    }

    ~LogService()
    {
        std::cout << std::endl;
        if (LOG_DEBUG)
            outputLog(debug, __FILE__, std::to_string(__LINE__), std::time(nullptr), "~LogService() succeed");
    }

    // 核心日志函数
    void log(LogLevel level, const char* file, int lineNum, const std::string& format, ...)
    {
#if LOG_SWITCH
        // 如果该级别的日志被关闭，则直接返回，不进行输出
        if (!_levelSwitchs[level])
            return;

        va_list args;
        va_start(args, format);

        // 使用 vector 替代固定大小的数组
        std::vector<char> messageBuffer(LOG_BUFFER_SIZE);

        size_t originalBufferSize = messageBuffer.size();  // 保存原始的缓冲区大小
        size_t bufferSize = originalBufferSize;
        bool bufferResized = false;  // 标志位，标记是否进行了扩容操作

        // 获取当前时间戳
        std::time_t time_t_now = std::time(nullptr);

        // 尝试格式化字符串
        int result = vsnprintf(messageBuffer.data(), bufferSize, format.c_str(), args);
        if (result < 0) {
            // 格式化失败，记录错误并退出
            outputLog(fatal, __FILE__, std::to_string(__LINE__), time_t_now, "日志信息格式化失败");
            va_end(args);
            return;
        }

        // 如果缓冲区不足，动态扩展
        while (result >= static_cast<int>(bufferSize)) {
            bufferSize *= 2; // 将缓冲区大小翻倍
            messageBuffer.resize(bufferSize);
            bufferResized = true;  // 标记为已扩容

            // 再次尝试格式化
            result = vsnprintf(messageBuffer.data(), bufferSize, format.c_str(), args);
            if (result < 0) {
                outputLog(fatal, __FILE__, std::to_string(__LINE__), time_t_now, "日志缓冲区扩展失败，或日志信息格式化失败");
                messageBuffer.resize(originalBufferSize);  // 恢复到原始大小
                va_end(args);
                return;
            }
        }

        va_end(args);

        // 缓存一些常用字符串

        const std::string& fileName = file;
        const std::string lineStr = std::to_string(lineNum);

        outputLog(level, fileName, lineStr, time_t_now, messageBuffer.data());

        // 如果进行了扩容，则恢复原始缓冲区大小
        if (bufferResized)
            messageBuffer.resize(originalBufferSize);  // 恢复到原始大小

#endif // LOG_SWITCH
    }


    // 设置日志级别开关（启用/禁用）
    LogService& setLevelSwitch(bool enabled, LogLevel level1 = level_count, LogLevel level2 = level_count,
        LogLevel level3 = level_count, LogLevel level4 = level_count, LogLevel level5 = level_count)
    {
        std::lock_guard<std::mutex> lock(mutex);

        // 如果没有传入任何日志级别，则将所有日志级别初始化为 enabled
        if (level1 == level2 && level2 == level3 && level3 == level4
            && level4 == level5 && level5 == level_count) {
            for (uint8_t i = 0; i < _levelSwitchs.size(); i++) {
                _levelSwitchs[i] = enabled;
            }
        }

        // 用于标记是否已经处理过某个日志级别
        bool seenLevels[level_count] = { false };
        for (LogLevel level : {level1, level2, level3, level4, level5}) {
            if (level == level_count) continue;
            // 检查是否有重复的日志级别
            if (seenLevels[level])
                throw std::runtime_error("设置日志开关时发现传入重复的日志级别：" + std::to_string(level));

            // 设置日志级别的开关状态
            if (level < level_count)
                _levelSwitchs[level] = enabled;
            else
                throw std::runtime_error("无效的日志级别：" + std::to_string(level));

            // 标记该日志级别为已见
            seenLevels[level] = true;
        }

        return *this;
    }

    // 设置日志文件路径
    LogService& setLogFilePaths(const FileRule& fileRule, LogLevel level1 = level_count, LogLevel level2 = level_count,
        LogLevel level3 = level_count, LogLevel level4 = level_count, LogLevel level5 = level_count)
    {
        std::lock_guard<std::mutex> lock(mutex);

        if (level1 == level2 && level2 == level3 && level3 == level4
            && level4 == level5 && level5 == level_count) {
            // 如果没有传入任何日志级别，则将所有日志级别初始化为 filePath
            for (FileRule& _fileRule : _logFileRules) {
                _fileRule = fileRule;
            }
        }

        bool seenLevels[level_count] = { false };

        for (LogLevel level : {level1, level2, level3, level4, level5}) {
            if (level == level_count) continue;
            if (seenLevels[level])
                throw std::runtime_error("设置日志保存路径时发现传入重复的日志级别：" + std::to_string(level));

            // 检查日志级别是否有效并设置对应的文件路径
            if (level < level_count)
                _logFileRules[level] = fileRule;
            else
                throw std::runtime_error("无效的日志级别：" + std::to_string(level));

            seenLevels[level] = true;  // 标记该日志级别为已见
        }

        return *this;
    }

    void applyRules()
    {
        for (FileRule& fileRule : _logFileRules) {
            _logFileNodeManager.addFileRule(fileRule._filePath,
                fileRule._genPolicy, fileRule._genValue,
                fileRule._purgePol, fileRule._genValue);
        }
        _logFileNodeManager.applyRules();
    }


private:

    // 封装输出操作
    void outputLog(LogLevel level, const std::string& filePath, const std::string& lineNum,
        const std::time_t time_t_now, const char* messageBuffer)
    {
        const std::string timestamp = timestampToString(time_t_now);
        const std::string& levelStr = gLevelMap[level];
        // 输出到控制台
        if (LOG_TO_CONSOLE)
            outputToConsole(level, filePath, lineNum, timestamp, levelStr, messageBuffer);

        // 输出到文件
        if (LOG_TO_FILE)
            outputToFile(level, filePath, lineNum, timestamp, time_t_now, levelStr, messageBuffer);
    }


    // 输出到控制台的函数
    void outputToConsole(LogLevel level, const std::string& file, const std::string& lineNum,
        const std::string& timestamp, const std::string& levelStr, const char* messageBuffer)
    {
        const char* colorCode = getLogLevelColor(level);

        std::string msg;
        msg += colorize("[" + levelStr + "]", colorCode) + " "
            + colorize("[" + file + "]", GREEN) + " "
            + colorize("[" + lineNum + "]", BLUE) + " "
            + colorize("[" + timestamp + "]", MAGENTA) + " ";

        msg += colorize(messageBuffer, colorCode);
        msg += "\n";

        std::cout << msg;
        // printf("%s", msg.c_str());
    }

    // 输出到文件的函数
    void outputToFile(LogLevel level, const std::string& file, const std::string& lineNum,
        const std::string& timestamp, std::time_t time_t_now, const std::string& levelStr, const char* messageBuffer)
    {
        // 获取最终的日志内容
        std::string fileLog;
        fileLog += "[" + levelStr + "] "
            + "[" + file + "] "
            + "[" + lineNum + "] "
            + "[" + timestamp + "] "
            + messageBuffer + "\n";

        // 写入文件
        _logFileNodeManager.writeToFile(_logFileRules[level]._filePath, fileLog, time_t_now);
    }

    // 时间戳转字符串（格式: YYYY-MM-DD HH:MM:SS）
    std::string timestampToString(std::time_t time_t_now)
    {
        // 线程安全地获取本地时间
        struct tm tm_buf;
#ifdef _WIN32
        localtime_s(&tm_buf, &time_t_now); // Windows 平台
#else
        localtime_r(&time_t_now, &tm_buf); // Linux/macOS 平台
#endif
        // 固定大小的缓冲区
        char buffer[24]; // "YYYY-MM-DD HH:MM:SS" 长度为 19 字节，加上终止符 '\0' 共 20 字节
        strftime(buffer, sizeof(buffer), "%Y-%m-%d %H:%M:%S", &tm_buf);

        // 返回结果
        return std::string(buffer);
    }

    // 获取带颜色的字符串（仅控制台使用）
    std::string colorize(const std::string& text, const char* colorCode)
    {
#if defined(LOG_TO_CONSOLE) && LOG_TO_CONSOLE
        return colorCode + text + RESET;
#else
        return text; // 文件日志忽略颜色
#endif
    }

    // 提取颜色映射
    const char* getLogLevelColor(LogLevel level)
    {
        switch (level) {
            case debug:
                return BOLD_WHITE;
            case info:
                return BOLD_CYAN;
            case warn:
                return BOLD_YELLOW;
            case error:
                return BOLD_RED;
            case fatal:
                return BOLD_MAGENTA;
            default:
                return BOLD_WHITE;
        }
    }

    // 设置 UTF-8 编码的函数
    void setUtf8Encoding()
    {
#ifdef _WIN32
        // Windows 平台
        SetConsoleOutputCP(65001); // 设置控制台输出编码为 UTF-8
#else
        // Linux 和 macOS 平台
        std::locale::global(std::locale("en_US.UTF-8")); // 设置全局本地化环境为 UTF-8
        std::wcout.imbue(std::locale("en_US.UTF-8"));    // 设置宽字符输出为 UTF-8
        std::cout.imbue(std::locale("en_US.UTF-8"));    // 设置标准输出为 UTF-8
#endif
    }

private:
    // 构造函数和析构函数
    LogService()
    {
        // 设置输出为 UTF-8 编码
        setUtf8Encoding();

        // 初始化日志级别开关
        _levelSwitchs.resize(level_count, 1); // 1 表示 true，0 表示 false
        _logFileRules.resize(level_count);
        if (LOG_TO_FILE) {
            // 设置所有级别的日志文件初始路径为 LOGFILE
            _logFileNodeManager.addFileRule(LOGFILE)
                .applyRules();
        }
    }

    // 单例模式相关
    static std::unique_ptr<LogService> _instance; // 使用智能指针管理单例
    static std::once_flag _onceFlag;          // 单例模式辅助工具

    std::vector<char> _levelSwitchs;        // 日志级别开关，默认全部打开
    std::vector<FileRule> _logFileRules; // 各级别日志文件存放路径
    LogFileNodeManager _logFileNodeManager;  // 日志文件管理器

    std::mutex mutex;
};
// 静态成员初始化
std::unique_ptr<LogService>  LogService::_instance = nullptr;
std::once_flag  LogService::_onceFlag;
}
}